package com.atguigu.srb.core.service.impl;

import com.atguigu.srb.base.consts.SmsConsts;
import com.atguigu.srb.base.util.Asserts;
import com.atguigu.srb.base.util.JwtUtils;
import com.atguigu.srb.common.result.ResponseEnum;
import com.atguigu.srb.common.util.MD5;
import com.atguigu.srb.common.util.RegexValidateUtils;
import com.atguigu.srb.core.entity.UserInfo;
import com.atguigu.srb.core.entity.vo.UserCenterIndexVo;
import com.atguigu.srb.core.entity.vo.UserInfoVo;
import com.atguigu.srb.core.mapper.UserInfoMapper;
import com.atguigu.srb.core.service.UserInfoService;
import com.atguigu.srb.core.service.UserLoginRecordService;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.commons.lang3.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
import java.util.UUID;


/**
 * <p>
 * 用户基本信息 服务实现类
 * </p>
 *
 * @author Atguigu
 * @since 2023-06-30
 */
@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {
    //code存入redis数据库的时候使用的是StringRedisTemplate,所以这里必须使用相同类型的对象去查询
    //否则查出来的数据会有问题
    @Resource
    StringRedisTemplate stringRedisTemplate;
    @Resource
    UserLoginRecordService userLoginRecordService;
    @Resource
    UserInfoMapper userInfoMapper;
    //用户注册的核心业务代码
    @Override
    public void registry(UserInfoVo userInfoVo) {
        //1.校验前端传过来的参数是否都ok,首先所有的参数都不能为空
        Integer userType = userInfoVo.getUserType();
        String code = userInfoVo.getCode();
        String mobile = userInfoVo.getMobile();
        String password = userInfoVo.getPassword();
        //1.1userType不能为空
        Asserts.AssertNotNull(userType, ResponseEnum.USER_TYPE_ERROR);
        //1.2.1验证码不能为空
        Asserts.AssertNotTrue(StringUtils.isEmpty(code),ResponseEnum.CODE_NULL_ERROR);
        //1.2.2验证码必须正确
        String redisCode = stringRedisTemplate.opsForValue().get(SmsConsts.SMS_CODE_KEY_PREFIX + mobile);
        Asserts.AssertTrue(StringUtils.equals(code,redisCode),ResponseEnum.CODE_ERROR);
        //1.3手机号码不能为空,而且要符合正则标准
        Asserts.AssertTrue(!StringUtils.isEmpty(mobile) && RegexValidateUtils.checkCellphone(mobile),
                ResponseEnum.MOBILE_NULL_ERROR);
        //1.4密码不能为空
        Asserts.AssertNotTrue(StringUtils.isEmpty(password),ResponseEnum.PASSWORD_NULL_ERROR);
        //2.需要查询判断是否已经注册过了
        int count = this.count(Wrappers.lambdaQuery(UserInfo.class).eq(UserInfo::getMobile, mobile)
                .eq(UserInfo::getUserType,userType));
        Asserts.AssertNotTrue(count != 0,ResponseEnum.MOBILE_EXIST_ERROR);
        //3.对密码进行加密
        //3.1修改UserInfo类,增加一个salt的属性
        //ALTER TABLE user_info ADD COLUMN salt CHAR(6) NOT NULL COMMENT '密码盐' AFTER PASSWORD;
        //生成盐
        String salt = UUID.randomUUID().toString().replace("-", "").substring(0, 6);
        String encryptPassword = MD5.encrypt(MD5.encrypt(password) + salt);

        //4.将用户插入数据库,完整注册
        //复制vo对象里面的属性给userInfo
        UserInfo userInfo = new UserInfo();
        BeanUtils.copyProperties(userInfoVo,userInfo);
        //将salt设置到userInfo里面
        userInfo.setSalt(salt);
        //将密码设置到userInfo里面
        userInfo.setPassword(encryptPassword);
        //设置userInfo的昵称和用户的头像
        userInfo.setNickName("user"+UUID.randomUUID().toString().substring(0,8));
        userInfo.setHeadImg("https://obsidiantuchuanggavin.oss-cn-beijing.aliyuncs.com/img/20180629210546_CQARA.jpeg");
        boolean save = this.save(userInfo);
        //5.删除redis中的验证码
        stringRedisTemplate.delete(SmsConsts.SMS_CODE_KEY_PREFIX + mobile);
    }

    @Override
    public String login(UserInfo userInfo, HttpServletRequest request) {
        //1.校验前端传过来的参数是否正确
        Integer userType = userInfo.getUserType();
        String mobile = userInfo.getMobile();
        String password = userInfo.getPassword();
        //1.1userType不能为空
        Asserts.AssertNotNull(userType, ResponseEnum.USER_TYPE_ERROR);
        //1.2手机号码不能为空,而且要符合正则标准
        Asserts.AssertTrue(!StringUtils.isEmpty(mobile) && RegexValidateUtils.checkCellphone(mobile),
                ResponseEnum.MOBILE_NULL_ERROR);
        //1.3密码不能为空
        Asserts.AssertNotTrue(StringUtils.isEmpty(password),ResponseEnum.PASSWORD_NULL_ERROR);
        //2.根据手机号查询会员的数据
        //select * from user_info where is_deleted = 0 and user_type = userType and user_mobile = mobile limit 0,1
        //避免有多个相同的用户,我们默认只查询最新的(跳过0个,显示一个)
        userInfo = this.getOne(Wrappers.lambdaQuery(UserInfo.class).eq(UserInfo::getUserType,userType)
                //last意思是在sql语句后面追加的语句
                .eq(UserInfo::getMobile,mobile).last("limit 0,1"));

        //----------------------------------如果还没有注册,提示用户不存在
        Asserts.AssertNotNull(userInfo,ResponseEnum.LOGIN_MOBILE_ERROR);
        //----------------------------------

        //3.判断密码是否正确
        String encryptPassword = MD5.encrypt(MD5.encrypt(password) + userInfo.getSalt());
        Asserts.AssertTrue(StringUtils.equals(encryptPassword,userInfo.getPassword()),ResponseEnum.LOGIN_PASSWORD_ERROR);

        //保存用户的登录的日志
        userLoginRecordService.saveLoginRecord(userInfo,request);

        //4.创建token返回
        //暂时还没有用户的name,所以使用nicekName来创建token
        return JwtUtils.createToken(userInfo.getId(),userInfo.getNickName());
    }

    @Override
    public UserInfo getInfo(String token) {
        //根据token判断是否合法
        Asserts.AssertTrue(JwtUtils.checkToken(token),ResponseEnum.WEIXIN_FETCH_ACCESSTOKEN_ERROR);
        //token合法的话,根据token解析出对应的id
        Long userId = JwtUtils.getUserId(token);
        //根据id查询userInfo
        UserInfo userInfo = this.getById(userId);
        //返回userInfo前,需要将敏感信息清楚,避免信息泄露
        userInfo.setSalt(null);
        // userInfo.setBindCode(null);
        userInfo.setOpenid(null);
        userInfo.setEmail(null);
        // userInfo.setIdCard(null);
        userInfo.setName(null);
        userInfo.setPassword(null);
        // userInfo.setMobile(null);
        //返回用户的信息,用来显示
        return userInfo;
    }

    @Override
    public UserCenterIndexVo getUserInfo(String token) {
        //根据token获取到用户的相关的信息,然后去数据库中查询数据并最终返回
        //1.首先根据token获取到用户的id,如果token过期货期签名有问题会获取失败的
        Long userId = JwtUtils.getUserId(token);
        //2.根据用户的id查询对应的数据,这个地方要使用三表联合查询,自定义sql语句
        UserCenterIndexVo userCenterIndexVo = baseMapper.getUserInfoById(userId);
        return userCenterIndexVo;
    }

    @Override
    public Page<UserInfo> pageList(UserInfo userInfo,Integer pageNum, Integer pageSize) {
        //创建page对象
        Page<UserInfo> pageList = new Page<>(pageNum,pageSize);
        //创建wrapper对象
        String mobile = userInfo.getMobile();
        Integer userType = userInfo.getUserType();
        Integer status = userInfo.getStatus();
        LambdaQueryWrapper<UserInfo> wrapper = Wrappers.lambdaQuery(UserInfo.class);
        if(StringUtils.isNotEmpty(userInfo.getMobile())){
            //like %mobile%
            //likeLeft %mobile
            //likeRight mobile%
            wrapper.like(UserInfo::getMobile,mobile);
        }
        if(userType != null){
            wrapper.eq(UserInfo::getUserType,userType);
        }
        if(userType != null){
            wrapper.eq(UserInfo::getStatus,status);
        }
        //查询的结果会放到pageList里面
        userInfoMapper.selectPage(pageList,wrapper);
        System.out.println("pageList = " + pageList);
        return pageList;
    }

    @Override
    public UserInfo updateUserInfo(String token, String mobile, Integer userType) {
        Long userId = JwtUtils.getUserId(token);
        //这个地方获取到的用户的id应该不会为空吧
        Asserts.AssertNotNull(userId,ResponseEnum.LOGIN_MOBILE_ERROR);
        /* this.update(Wrappers.lambdaUpdate(UserInfo.class).eq(UserInfo::getId,userId)
                .set(UserInfo::getMobile,mobile)
                .set(UserInfo::getUserType,userType)
                //因为手动更新的,所以需要再更新一下updateTime
                .set(UserInfo::getUpdateTime,new Date()));
        //再将更新后的对象返回
        return this.getById(userId); */
        //先查询获取userInfo
        UserInfo userInfo = this.getById(userId);
        userInfo.setMobile(mobile);
        userInfo.setUserType(userType);
        //更新userInfo的信息
        this.updateById(userInfo);
        //返回前将用户的敏感信息清空
        // userInfo.setSalt(null);
        userInfo.setBindCode(null);
        userInfo.setOpenid(null);
        userInfo.setEmail(null);
        // userInfo.setIdCard(null);
        userInfo.setName(null);
        userInfo.setPassword(null);
        // userInfo.setMobile(null);
        return userInfo;
    }

    //根据token判断账户是否有绑定hfb的账号
    @Override
    public UserInfo checkUserInfoByToken(String token) {
        Long userId = JwtUtils.getUserId(token);
        return this.checkUserInfoByUserId(userId);
    }

    //根据userId判断账户是否有不好看hfb的账号
    @Override
    public UserInfo checkUserInfoByUserId(Long userId) {
        UserInfo userInfo = this.getById(userId);
        Asserts.AssertTrue(userInfo.getBindStatus().intValue() == 1,ResponseEnum.USER_NO_BIND_ERROR);
        return userInfo;
    }


}
